/**
 * 先执行 install 方法然后执行 constructor 构造函数接着在执行 install 中 _Vue.mixin 的  beforeCreate
 * 1. 在创建路由实例的时候先 Vue.use() 主要是调用插件内部的 install 方法这个方法接收一个vue构造函数为参数，判断是否注册没有的话则进行注册，创建一个全局变量用于接收Vue方便后续使用，并且通过 vue 的 mixin 混入, mixin 接收一个对象作为参数在 beforeCreate 钩子中把 router 对象注入到 Vue 实例中，并调用 init 初始化方法
 * 2. 实例方法就是只有实例可以调用，静态方法只有构造函数可以调用，原型方法是实例和构造函数都可以调用，是共享的方法。所依这里的静态方法不能通过 this 实例来调用或添加属性只能通过构造函数即 VueRouter 进行调用
 * 3. createRouteMap 遍历所有路由规则把路由规则解析成键值对的形式，键就是路由地址，值就是对应的组件
 * 4. 然后通过 initComponents 方法去创建 router-link 和 router-view 组件
 * 5. initEvent 方法是点击浏览器前进后退时重新给当前所在的路由对象current属性赋值，因为这个属性是动态的所以会重新渲染对应组件
 */
let _Vue = null
export default class VueRouter {
  static install (Vue) {
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true
    _Vue = Vue
    _Vue.mixin({
      beforeCreate () {
        // 这里的this就是vue实例
        // 判断是vue构造函数时给原型加router，否则每个一组件的vue实例的原型都会给加上router
        // 判断是Vue构造函数，因为只有通过new Vue创建实例时才有router这个参数
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
          // 添加完router对象后需要执行createRouteMap和initComponents方法，为了方便调用统一放到init方法中调用
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    // options就是我们使用VueRouter构造函数时传递过来的对象，这个对象中就有我们的路由规则
    this.options = options
    // 路由地址和组件的对应关系
    this.routeMap = {}
    // 当前所在的路由对象current属性则是当前所在路由
    this.data = _Vue.observable({
      current: '/#/'
    })
  }

  init () {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouteMap () {
    console.log(location)
    if (location.pathname === '/') {
      this.defaultHash()
    }
    this.options.routes.forEach(route => {
      const path = route.path.replace(/\/?/, '/#/')
      this.routeMap[path] = route.component
    })
  }

  initComponents (Vue) {
    // h方法会创建一个虚拟dom参数一是选择器，也就是你要创建的元素，参数二是设置这个元素的属性，第三个参数是这个元素的子元素
    Vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander (e) {
          history.pushState({}, '', this.to.replace(/\/?/, '/#/'))
          this.$router.data.current = this.to.replace(/\/?/, '/#/')
          e.preventDefault()
        }
      }
    })
    const self = this
    Vue.component('router-view', {
      render (h) {
        const cm = self.routeMap[self.data.current]
        return h(cm)
      }
    })
  }

  initEvent () {
    window.addEventListener('popstate', () => {
      // 当是history模式时使用window.location.pathname当前浏览器地址栏的路径部分，当是hash模式时使用window.location.hash
      let pathStr = ''
      if (window.location.hash) {
        pathStr = '/' + window.location.hash
      } else {
        pathStr = '/#/'
        this.defaultHash()
      }
      this.data.current = pathStr
    })
  }

  defaultHash () {
    history.pushState({}, '', '/#/')
  }
}
